import * as utils from '../utils'
import { mat4, vec3, quat } from 'gl-matrix'

function createCourse32 (gl: WebGLRenderingContext, dom: HTMLCanvasElement) {
  gl.enable(gl.DEPTH_TEST)
  gl.clearColor(0.0, 0.0, 0.0, 1.0)
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

  const vectexShaderSrc = `
    uniform mat4 u_MvpMatrix;
    uniform mat4 u_NormalMatrix;
    uniform vec3 u_LightPosition;
    uniform vec3 u_LightColor;
    uniform vec3 u_AmbientLight;
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    attribute vec4 a_Normal;
    varying vec4 v_Color;
    void main() {
        gl_Position = u_MvpMatrix * a_Position;
        vec3 ambient = u_AmbientLight * a_Color.rgb;
        vec3 normal = normalize(a_Normal.xyz);
        float nDotL = max(dot(u_LightPosition, normal), 0.0);
        vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;
        v_Color = vec4(diffuse + ambient, a_Color.a);
    }
  `

  const fragmentShaderSrc = `
  precision mediump float;
  varying vec4 v_Color;
    void main() {
        gl_FragColor = v_Color;
    }
  `

  const program = utils.initShaders(gl, vectexShaderSrc, fragmentShaderSrc)

  // Vertex coordinates（a cuboid 3.0 in width, 10.0 in height, and 3.0 in length with its origin at the center of its bottom)
  const vertices = new Float32Array([
    1.5, 10.0, 1.5, -1.5, 10.0, 1.5, -1.5, 0.0, 1.5, 1.5, 0.0, 1.5, // v0-v1-v2-v3 front
    1.5, 10.0, 1.5, 1.5, 0.0, 1.5, 1.5, 0.0, -1.5, 1.5, 10.0, -1.5, // v0-v3-v4-v5 right
    1.5, 10.0, 1.5, 1.5, 10.0, -1.5, -1.5, 10.0, -1.5, -1.5, 10.0, 1.5, // v0-v5-v6-v1 up
    -1.5, 10.0, 1.5, -1.5, 10.0, -1.5, -1.5, 0.0, -1.5, -1.5, 0.0, 1.5, // v1-v6-v7-v2 left
    -1.5, 0.0, -1.5, 1.5, 0.0, -1.5, 1.5, 0.0, 1.5, -1.5, 0.0, 1.5, // v7-v4-v3-v2 down
    1.5, 0.0, -1.5, -1.5, 0.0, -1.5, -1.5, 10.0, -1.5, 1.5, 10.0, -1.5 // v4-v7-v6-v5 back
  ])

  const colors = new Float32Array([
    1.0, 0.3, 0.3, 1.0, 0.3, 0.3, 1.0, 0.3, 0.3, 1.0, 0.3, 0.3,
    1.0, 0.3, 0.3, 1.0, 0.3, 0.3, 1.0, 0.3, 0.3, 1.0, 0.3, 0.3,
    1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4,
    1.0, 0.7, 1.0, 1.0, 0.7, 1.0, 1.0, 0.7, 1.0, 1.0, 0.7, 1.0,
    1.0, 0.5, 0.1, 1.0, 0.5, 0.1, 1.0, 0.5, 0.1, 1.0, 0.5, 0.1,
    1.0, 0.5, 0.5, 1.0, 0.5, 0.5, 1.0, 0.5, 0.5, 1.0, 0.5, 0.5
  ])

  // Normal
  const normals = new Float32Array([
    0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
    1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
    0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
    -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
    0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, // v7-v4-v3-v2 down
    0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0 // v4-v7-v6-v5 back
  ])

  // Indices of the vertices
  const indices = new Uint8Array([
    0, 1, 2, 0, 2, 3, // front
    4, 5, 6, 4, 6, 7, // right
    8, 9, 10, 8, 10, 11, // up
    12, 13, 14, 12, 14, 15, // left
    16, 17, 18, 16, 18, 19, // down
    20, 21, 22, 20, 22, 23 // back
  ])

  // 定点缓冲区
  const verticsBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, verticsBuffer)
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
  const vertorSize = vertices.BYTES_PER_ELEMENT
  const aPosition = gl.getAttribLocation(program, 'a_Position')
  gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, vertorSize * 3, 0)
  gl.enableVertexAttribArray(aPosition)

  const colorBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
  gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW)
  const colorSize = colors.BYTES_PER_ELEMENT
  const aColor = gl.getAttribLocation(program, 'a_Color')
  gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, colorSize * 3, 0)
  gl.enableVertexAttribArray(aColor)

  const aNormal = gl.getAttribLocation(program, 'a_Normal')
  const normalBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer)
  gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW)
  const normalSize = normals.BYTES_PER_ELEMENT
  gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, normalSize * 3, 0)
  gl.enableVertexAttribArray(aNormal)

  // 平行光源位置
  const directionLightPosition = vec3.create()
  vec3.set(directionLightPosition, 0.0, 1.0, 1.0)
  vec3.normalize(directionLightPosition, directionLightPosition)
  const directionLightColor = vec3.create()
  vec3.set(directionLightColor, 1.0, 1.0, 1.0)
  const uLightPosition = gl.getUniformLocation(program, 'u_LightPosition')
  gl.uniform3fv(uLightPosition, directionLightPosition)
  const uLightColor = gl.getUniformLocation(program, 'u_LightColor')
  gl.uniform3fv(uLightColor, directionLightColor)

  // 环境光颜色
  const ambientLight = vec3.create()
  vec3.set(ambientLight, 0.2, 0.2, 0.2)
  const uAmbientLight = gl.getUniformLocation(program, 'u_AmbientLight')
  gl.uniform3fv(uAmbientLight, ambientLight)

  // 索引缓冲区
  const indexBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW)

  // arm1的模型矩阵
  const arm1ModelMatrix = mat4.create()
  const axis = vec3.create()
  vec3.set(axis, 1.0, 1.0, 1.0)
  mat4.fromRotation(arm1ModelMatrix, 0.0, axis)

  const normalMatrix = mat4.create()
  mat4.invert(normalMatrix, arm1ModelMatrix)
  mat4.transpose(normalMatrix, normalMatrix)
  const uNormalMatrix = gl.getUniformLocation(program, 'u_NormalMatrix')

  // 观察矩阵
  const viewMatrix = mat4.create()
  const eye = vec3.create()
  vec3.set(eye, 20.0, 20.0, 40.0)
  const center = vec3.create()
  vec3.set(center, 0.0, 5.0, 0.0)
  const up = vec3.create()
  vec3.set(up, 0.0, 1.0, 0.0)
  mat4.lookAt(viewMatrix, eye, center, up)

  // 相机矩阵
  const projMatrix = mat4.create()
  mat4.perspective(projMatrix, 70, dom.offsetWidth / dom.offsetHeight, 0.01, 1000)

  const viewModelMatrix1 = mat4.create()
  mat4.multiply(viewModelMatrix1, viewMatrix, arm1ModelMatrix)

  const mvpMatrix1 = mat4.create()
  mat4.multiply(mvpMatrix1, projMatrix, viewModelMatrix1)

  gl.uniformMatrix4fv(uNormalMatrix, false, normalMatrix)

  const uMvpMatrix = gl.getUniformLocation(program, 'u_MvpMatrix')
  gl.uniformMatrix4fv(uMvpMatrix, false, mvpMatrix1)

  gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0)

  const arm2ModelMatrix = mat4.create()
  const rot = quat.create()
  quat.set(rot, 0.5, 0, 0, 1)
  const translate = vec3.create()
  vec3.set(translate, 0, 10, 0)
  const scale = vec3.create()
  vec3.set(scale, 1.3, 1, 1.3)
  mat4.fromRotationTranslationScale(arm2ModelMatrix, rot, translate, scale)

  mat4.invert(normalMatrix, arm2ModelMatrix)
  mat4.transpose(normalMatrix, normalMatrix)

  const viewModelMatrix2 = mat4.create()
  mat4.multiply(viewModelMatrix2, viewMatrix, arm2ModelMatrix)

  const mvpMatrix2 = mat4.create()
  mat4.multiply(mvpMatrix2, projMatrix, viewModelMatrix2)

  gl.uniformMatrix4fv(uNormalMatrix, false, normalMatrix)
  gl.uniformMatrix4fv(uMvpMatrix, false, mvpMatrix2)

  gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0)
}

export {
  createCourse32
}
